﻿using System;
using System.Collections;
using System.IO;
using System.Globalization;
using Microsoft.Office.Interop.Excel;

namespace LocalisationResourceManager
{
    /// <summary>
    /// The class for the collection of translations for a culture.
    /// </summary>
    public class TranslationSheet : Hashtable
    {
        private readonly string _culture;

        public TranslationSheet(string culture)
        {
            _culture = culture;
        }

        public void Add(string invariantString, string path, string name, string localizedValue)
        {
            ResourceRow entry = this[invariantString, path, name];
            entry.LocalizedValue = localizedValue;
            entry.IsANewResource = false;
        }

        public ResourceRow this[string invariantString, string path, string name]
        {
            get
            {
                invariantString = invariantString.Replace("\t", " ");

                if (invariantString.StartsWith("'"))
                    invariantString = invariantString.Substring(1);

                // Excel's default format uses "True" and "False".
                if (string.Compare(invariantString, "true", true) == 0)
                    invariantString = "True";

                if (string.Compare(invariantString, "false", true) == 0)
                    invariantString = "False";

                if (string.Compare(name, "true", true) == 0)
                    name = "True";

                if (string.Compare(name, "false", true) == 0)
                    name = "False";

                if (invariantString.Length > Lrm.MaxLengthAnExcelCellCanHold)
                    invariantString = invariantString.Substring(0, Lrm.MaxLengthAnExcelCellCanHold);

                if (!ContainsKey(invariantString))
                    this[invariantString] = new InvariantStringDictonary(invariantString, path, name, Lrm.ReplaceAltKey(invariantString), true);

                return ((InvariantStringDictonary)this[invariantString])[invariantString, path, name];
            }
        }

        // Save the changes.
        public void Save()
        {
            System.Reflection.Missing missing = System.Reflection.Missing.Value;

            if (IsSupportdCultureInfo(CultureTypes.SpecificCultures, _culture))
                return;

            // prepare the Excel file.
            var oEa = new Application();
            Workbooks oWBs = oEa.Workbooks;

            _Workbook oWb;

            bool xlsExits = File.Exists(XlsFile);
            if (xlsExits)
            {
                Lrm.SetFileWritable(XlsFile);

                // You may need to modify this method if you are not using Excel 11.0.
                oWBs.Open(XlsFile, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing);
                oWb = oWBs[1];
            }
            else
                oWb = oEa.Workbooks.Add(missing);

            _Worksheet oSheet = null;

            foreach (Worksheet sheet in oWb.Sheets)
                if (sheet.Name == _culture)
                {
                    oSheet = sheet;
                    break;
                }

            bool createNewSheet = false;

            // create the sheet if needed.
            if (oSheet == null)
            {
                oSheet = (Worksheet)oWb.Sheets.Add(missing, missing, missing, missing);
                oSheet.Name = _culture;

                createNewSheet = true;
            }

            var list = new ArrayList();

            // prepare the data.
            foreach (DictionaryEntry w in this)
            {
                var wg = (InvariantStringDictonary)w.Value;

                foreach (DictionaryEntry p in wg)
                {
                    var pg = (ResourcePath)p.Value;

                    bool savedOne = false;

                    foreach (DictionaryEntry e in pg)
                    {
                        var entry = (ResourceRow)e.Value;

                        if (entry.IsANewResource)
                        {
                            list.Add(new[] { entry.InvariantStringValue, entry.LocalizedValue, entry.ResourceName, entry.ResourceFilePath, "Y" });

                            savedOne = true;

                            if (Lrm.WriteUniqueResourceOnly)
                                break;
                        }
                    }

                    if (Lrm.WriteUniqueResourceOnly && savedOne)
                        break;
                }
            }

            if (list.Count > 0)
            {
                // assign the data to the sheet.
                Range oRange = oSheet.get_Range("A" + (oSheet.UsedRange.Rows.Count + (createNewSheet ? 0 : 1)), missing);
                oRange = oRange.get_Resize(list.Count, 5);

                var a = new object[list.Count, 5];

                for (int i = 0; i < list.Count; i++)
                {
                    var v = (object[])list[i];

                    for (int j = 0; j < 5; j++)
                        a[i, j] = v[j];
                }

                oRange.Value2 = a;
            }

            // save it.
            if (createNewSheet || list.Count > 0)
            {
                if (xlsExits)
                    oWb.Save();
                else
                    oWb.SaveAs(XlsFile, XlFileFormat.xlXMLSpreadsheet, missing, missing, missing, missing, XlSaveAsAccessMode.xlExclusive, missing, missing, missing,
                               missing, missing);
            }

            oWb.Close(null, null, null);
            oWBs.Close();
            oEa.Quit();
        }

        public DateTime LastModified
        {
            get
            {
                if (File.Exists(_xlsFile))
                    return File.GetLastWriteTime(_xlsFile);
                
                return DateTime.Now;
            }
        }

        private string _xlsFile = string.Empty;

        public string XlsFile
        {
            get
            {
                if (_xlsFile == string.Empty)
                {
                    _xlsFile = IsSupportdCultureInfo(CultureTypes.AllCultures, _culture) ? Path.Combine(Lrm.ResourceRepositoryPath, _culture + ".xls") : Path.Combine(Lrm.ResourceRepositoryPath, "Excluded.xls");
                }

                return _xlsFile;
            }
            set { _xlsFile = value; }
        }

        private static Hashtable _allCultures;
        private static Hashtable _specificCultures;

        //  Find out if a culture is any supported culture or if it is a specific culture.
        internal static bool IsSupportdCultureInfo(CultureTypes type, string culture)
        {
            // cache two kinds of supported cultures, any type or specific.
            if (_allCultures == null)
            {
                _allCultures = new Hashtable();
                _specificCultures = new Hashtable();

                foreach (CultureInfo c in CultureInfo.GetCultures(CultureTypes.AllCultures))
                {
                    _allCultures.Add(c.Name, 1);
                    if (!c.IsNeutralCulture)
                    {
                        _specificCultures.Add(c.Name, 1);
                    }
                }
            }

            if (type == CultureTypes.AllCultures)
                return _allCultures.ContainsKey(culture);
            if (type == CultureTypes.SpecificCultures)
                return _specificCultures.ContainsKey(culture);
            
            throw new ArgumentException("CultureType not supported.");
        }
    }
}
